<?php
require SYSTEM_PATH . '/common/constants.php'; // 加载常量
require SYSTEM_PATH . '/common/functions.php'; // 加载核心函数库
require SYSTEM_PATH . '/Logger.php'; // 日志记录类

require SYSTEM_PATH . '/Dispatcher.php'; // 路由分派类
require SYSTEM_PATH . '/Controller.php'; // controller抽象类
require SYSTEM_PATH . '/Model.php'; // model抽象类

require SYSTEM_PATH . '/TaskQueue.php'; // 任务队列类
/**
 * 应用程序类
 *
 * @author vincent
 *        
 */
class Mikasa {
	
	/**
	 * 应用程序初始化
	 */
	private static function init() {
		// 加载默认配置
		$config = $GLOBALS ['CONFIG'] = include SYSTEM_PATH . '/common/default_config.php';
		
		// 是否开启DEBUG模式
		if ($config ['DEBUG'] == true) {
			error_reporting ( E_ALL & ~ E_NOTICE & ~ E_WARNING ); // 报告除了提醒警告外错误(否则错误报告文件会有大量的提醒信息)
			ini_set ( 'display_errors', 1 ); // 显示错误
		}
		else {
			error_reporting ( 0 ); // 禁用错误报告
			ini_set ( 'display_errors', 0 ); // 不显示错误
		}
		
		// 设置系统时区
		date_default_timezone_set ( $config ['DEFAULT_TIMEZONE'] );
		
		// 设置session
		session_name ( $config ['SESSION_NAME'] );
		if ($config ['SESSION_AUTO_START'] == true) {
			session_start ();
		}
		
		// 设定错误和异常处理
		register_shutdown_function ( 'Mikasa::fatalError' );
		set_error_handler ( 'Mikasa::appError', E_ALL & ~ E_NOTICE & ~ E_WARNING );
		set_exception_handler ( 'Mikasa::appException' );
	}
	/**
	 * 应用开始
	 */
	public static function run() {
		// 应用初始化
		self::init ();
		// URL调度
		Dispatcher::dispatch ();
		
		// 加载自定义函数库
		if (file_exists ( MODULE_PATH . '/common/functions.php' )) {
			import ( MODULE_PATH . '/common/functions.php' );
		}
		// 加载自定义常量
		if (file_exists ( MODULE_PATH . '/common/constants.php' )) {
			import ( MODULE_PATH . '/common/constants.php' );
		}
		
		// 控制器文件路径
		$controllerClassPath = MODULE_PATH . '/controllers/' . CONTROLLER_NAME . '.php';
		if (file_exists ( $controllerClassPath ) && import ( $controllerClassPath )) {
			$controllerInstance = self::getControllerInstance ( CONTROLLER_NAME );
			$actionName = ACTION_NAME;
			// 调用controller的action处理用户请求
			$controllerInstance->$actionName ();
		}
		else {
			throw new Exception ( '控制器' . CONTROLLER_NAME . '不存在', 404 );
		}
	}
	
	/**
	 * 获取应用配置
	 *
	 * @param string $key 配置项
	 * @return NULL
	 */
	public static function getConfig($key) {
		if (isset ( $GLOBALS ['CONFIG'] [$key] ))
			return $GLOBALS ['CONFIG'] [$key];
		return NULL;
	}
	
	/**
	 * 创建controller实例(单例)
	 *
	 * @param string $controllerName controller类名
	 * @return Controller
	 */
	public static function getControllerInstance($controllerName) {
		import ( MODULE_PATH . '/controllers/' . ucfirst ( $controllerName ) . '.php' );
		return self::getInstance ( "\\" . MODULE_NAME . "\\controllers\\" . $controllerName );
	}
	/**
	 * 创建model实例(非单例)
	 *
	 * @param string $modelName model类名
	 * @return Model
	 */
	public static function getModelInstance($modelName) {
		import ( MODULE_PATH . '/models/' . ucfirst ( $modelName ) . '.php' );
		$className = "\\" . MODULE_NAME . "\\models\\" . $modelName;
		return new $className ();
	}
	
	/**
	 * 单例模式创建类的实例
	 *
	 * @param string $className 类名
	 * @return Ambigous <unknown>
	 */
	private static function getInstance($className) {
		static $_instances = array (); // 实例缓存
		if (! isset ( $_instances [$className] )) {
			$_instances [$className] = new $className ();
		}
		return $_instances [$className];
	}
	/**
	 * 显示页面不存在页面
	 */
	public static function pageNotFound() {
		include SYSTEM_PATH . '/tpl/404.php';
	}
	/**
	 * 显示自定义页面
	 *
	 * @param string $pageTitle 页面标题
	 * @param string $title 内容标题
	 * @param string $content 详细内容
	 */
	public static function toCustomPage($pageTitle, $title, $content = '') {
		include SYSTEM_PATH . '/tpl/custompage.php';
	}
	/**
	 * 重定向
	 *
	 * @param string $url
	 */
	public static function redirect($url) {
		header ( 'location:' . $url );
		exit ();
	}
	/**
	 * 自定义异常处理
	 *
	 * @param Exception $e 异常对象
	 */
	public static function appException($e) {
		// 异常详细内容
		$content = $e->getMessage () . '<br>异常文件:' . $e->getFile () . '<br>行号:' . $e->getLine ();
		$content .= '<br>' . $e->getTraceAsString ();
		// 是否记录异常(只记录非404异常)
		if ($GLOBALS ['CONFIG'] ['LOG_RECORD'] && $e->getCode () != 404) {
			Logger::log ( 'exception', $content );
		}
		// 调试模式才显示错误
		if ($GLOBALS ['CONFIG'] ['DEBUG'] == true) {
			self::toCustomPage ( '发生异常', $content );
			exit ();
		}
		else if ($e->getCode () == 404) {
			self::pageNotFound ();
			exit ();
		}
		send_http_status ( 500 );
		exit ();
	}
	/**
	 * 自定义错误处理
	 *
	 * @param int $errno 错误类型
	 * @param string $errstr 错误信息
	 * @param string $errfile 错误文件
	 * @param int $errline 错误行数
	 */
	public static function appError($errno, $errstr, $errfile, $errline) {
		// 错误详细内容
		$content = '错误级别:' . $errno . '<br>错误文件:' . $errfile . '<br>行号:' . $errline;
		// 是否记录错误
		if ($GLOBALS ['CONFIG'] ['LOG_RECORD']) {
			Logger::log ( 'error', $content );
		}
		// 调试模式下显示错误
		if ($GLOBALS ['CONFIG'] ['DEBUG'] == true) {
			self::toCustomPage ( '发生错误', $errstr, $content );
			exit ();
		}
		else {
			send_http_status ( 500 );
			exit ();
		}
	}
	/**
	 * 致命错误捕获
	 */
	public static function fatalError() {
		$error = error_get_last ();
		if ($error ['type'] == E_ERROR) {
			// 错误详细内容
			$content = '错误级别:' . E_ERROR . '<br>错误文件:' . $error ['file'] . '<br>行号:' . $error ['line'];
			// 是否记录错误
			if ($GLOBALS ['CONFIG'] ['LOG_RECORD']) {
				Logger::log ( 'error', $content );
			}
			// 调试模式下显示错误
			if ($GLOBALS ['CONFIG'] ['DEBUG'] == true) {
				self::toCustomPage ( '发生致命错误', $error ['message'], $content );
			}
			else {
				send_http_status ( 500 );
				exit ();
			}
		}
	}
	/**
	 * 获取当前时间
	 *
	 * @return integer
	 */
	public static function getTime() {
		return $_SERVER ['REQUEST_TIME'];
	}
}
